import { MathUtils, Vect3 } from "../../../../common/MathUtils"
import { Comp } from "../../CompDef"
import { GpCfg } from "../../GpCfgDef"
import { GpEventDef } from "../../GpEventDef"
import { FindTargetCondition, EFindTargetConditionAttriType, EFindTargetMatchOpType, EHeroAttri, EHeroLogicType, EHeroTargetMatchType, HeroActionLogic, EHeroSpecialState, HeroLogic, PlayEffEventData, EHeroAttriModifyType, EHeroAttriOperationType } from "../../GpDef"
import { BattleSystem, CureEventInfo, DamageEventInfo } from "./BattleSystem"
import { BuffSystem } from "./BuffSystem"
import { gg } from "../../../../../Game"
import { EcsWorld, EcsEntity } from "ecs-ts"

/**进行攻击伤害结算 */
export function makeDamage(damageEventInfo: DamageEventInfo) {
    const world=damageEventInfo.world
    const battleAttri = damageEventInfo.entity.component(Comp.Battle.Attri)
    const atp = Comp.Battle.Attri.getValue(battleAttri, EHeroAttri.atp)
    damageEventInfo.value = atp
    damageEventInfo.targetBattleInfo.curHp = Math.max(0, MathUtils.fixNumber(damageEventInfo.targetBattleInfo.curHp - atp))
    gg.eventTarget.emit(GpEventDef.onDamage, damageEventInfo)
    if (damageEventInfo.targetBattleInfo.curHp <= 0 && damageEventInfo.target.component(Comp.Battle.Alive)) {
        world.removeComponent(damageEventInfo.target,Comp.Battle.Alive)
        world.addComponent(damageEventInfo.target,Comp.Battle.Dead).startTimeMs = damageEventInfo.world.elapsedTimeMs
        damageEventInfo.battleInfo.attTargetEntityId = 0
        damageEventInfo.entity.component(Comp.HeroAction).targetId = 0
        Vect3.set(damageEventInfo.entity.component(Comp.Transform).prefVelocity, Vect3.ZERO)
        // damageEventInfo.world.removeEntity(damageEventInfo.target.id)
    }
}

/**进行治疗结算 */
export function cure(cureEventInfo: CureEventInfo) {
    const battleAttri = cureEventInfo.target.component(Comp.Battle.Attri)
    const hp = Comp.Battle.Attri.getValue(battleAttri, EHeroAttri.hp)
    const atp = Comp.Battle.Attri.getValue(battleAttri, EHeroAttri.atp)
    cureEventInfo.targetBattleInfo.curHp = MathUtils.fixNumber(Math.min(hp, cureEventInfo.targetBattleInfo.curHp + atp))
    gg.eventTarget.emit(GpEventDef.onCure, cureEventInfo)

}

/**
 * 创建并初始化一个锁定目标的子弹实体。
 * @param world EcsWorld 实例，表示当前的游戏世界。
 * @param ownerEntity 发射子弹的实体。
 * @param battleInfo 包含战斗相关信息的组件，如子弹速度和攻击力等。
 * @param target 子弹的目标实体。
 * @param targetBattleInfo 目标实体的战斗信息组件。
 * @returns 返回创建的子弹实体。
 */
export function makeLockBullet(world: EcsWorld, ownerEntity: EcsEntity, battleInfo: Comp.Battle.BattleInfo, target: EcsEntity, targetBattleInfo: Comp.Battle.BattleInfo) {
    // 在世界中添加一个新的实体，并附带 Transform、Bullet 和 TargetLocker 组件
    const bullet = world.addEntityWithComps(
        [
            Comp.Transform,
            Comp.Battle.Bullet,
            Comp.Battle.TargetLocker,
        ],
        (e) => {
            // 获取发射者和目标的 Transform 组件以及发射者的 Force 组件
            const ownerTransform = ownerEntity.component(Comp.Transform)
            const force = ownerEntity.component(Comp.Force)
            const bulletTransform = e.component(Comp.Transform)
            const targetTransform = target.component(Comp.Transform)

            // 计算子弹方向和起始位置
            const targetPos = targetTransform.pos
            const direction = Vect3.subtract(Comp.Transform.tempVec3, targetPos, ownerTransform.pos)
            Vect3.normalize(direction, direction)
            const startPos = ownerTransform.pos// Vec3.add(Comp.Transform.tempVec3, ownerTransform.pos, Vec3.multiplyScalar(Comp.Transform.tempVec3, direction, ownerTransform.radius))
            Vect3.set(bulletTransform.pos, startPos)
            /**一个向上的偏移，让子弹比起点位置靠上一点 */
            Vect3.add(bulletTransform.pos, bulletTransform.pos, Vect3.set(Comp.Transform.tempVec3, 0, ownerTransform.height / 2, 0))

            // 设置子弹的目标锁定信息和基本属性
            const locker = e.component(Comp.Battle.TargetLocker)
            locker.targetEntityId = target.id
            Vect3.set(locker.targetPos, targetPos)

            const bullet = e.component(Comp.Battle.Bullet)
            bullet.emmiterId = ownerEntity.id
            bullet.speed = battleInfo.bulletSpeed
            const battleAttri = ownerEntity.component(Comp.Battle.Attri)
            const atp = Comp.Battle.Attri.getValue(battleAttri, EHeroAttri.atp)
            bullet.atp = atp
            bullet.forceId = force.value
            bullet.maxPassThrough = 1
        }
    )

    return bullet
}


/**
 * 创建并初始化一个子弹实体。
 * @param world 世界对象，用于添加新的实体。
 * @param ownerEntity 发射子弹的实体。
 * @param battleInfo 包含战斗相关信息的组件。
 * @param target 子弹的目标实体。
 * @param targetBattleInfo 目标实体的战斗信息组件。
 * @returns 返回创建的子弹实体。
 */
export function makeBullet(world: EcsWorld, ownerEntity: EcsEntity, battleInfo: Comp.Battle.BattleInfo, target: EcsEntity, targetBattleInfo: Comp.Battle.BattleInfo) {
    // 在世界中添加一个包含Transform和Bullet组件的新实体
    const bullet = world.addEntityWithComps(
        [
            Comp.Transform,
            Comp.Battle.Bullet,
            Comp.Battle.FlyBullet
        ],
        (e) => {
            // 获取发射实体的位置和力信息
            const ownerTransform = ownerEntity.component(Comp.Transform)
            const force = ownerEntity.component(Comp.Force)
            // 获取新创建的子弹实体的Transform组件
            const bulletTransform = e.component(Comp.Transform)
            // 获取目标实体的位置信息
            const targetTransform = target.component(Comp.Transform)
            const targetPos = targetTransform.pos

            // 设置子弹的起始位置
            const startPos = ownerTransform.pos// Vec3.add(Comp.Transform.tempVec3, ownerTransform.pos, Vec3.multiplyScalar(Comp.Transform.tempVec3, direction, ownerTransform.radius))
            Vect3.set(bulletTransform.pos, startPos)
            /**一个向上的偏移，让子弹比起点位置靠上一点 */
            Vect3.add(bulletTransform.pos, bulletTransform.pos, Vect3.set(Comp.Transform.tempVec3, 0, ownerTransform.height / 2, 0))

            // 计算子弹的运动方向
            const direction = Vect3.subtract(Comp.Transform.tempVec3, targetPos, bulletTransform.pos)
            Vect3.normalize(direction, direction)
            Vect3.set(bulletTransform.orientation, direction)

            // 获取并设置子弹的其他属性
            const bullet = e.component(Comp.Battle.Bullet)
            const battleAttri = e.component(Comp.Battle.Attri)
            const atp = Comp.Battle.Attri.getValue(battleAttri, EHeroAttri.atp)
            bullet.emmiterId = ownerEntity.id
            bullet.speed = battleInfo.bulletSpeed
            bullet.atp = atp
            bullet.forceId = force.value

        }
    )

    return bullet
}

/**
 * 创建并初始化一个激光实体。
 * @param world 世界对象，用于添加新的实体。
 * @param ownerEntity 发射子弹的实体。
 * @param battleInfo 包含战斗相关信息的组件。
 * @param target 子弹的目标实体。
 * @param targetBattleInfo 目标实体的战斗信息组件。
 * @returns 返回创建的子弹实体。
 */
export function makeRay(world: EcsWorld, ownerEntity: EcsEntity, battleInfo: Comp.Battle.BattleInfo, target: EcsEntity, targetBattleInfo: Comp.Battle.BattleInfo) {
    // 在世界中添加一个包含Transform和Bullet组件的新实体
    const bullet = world.addEntityWithComps(
        [
            Comp.Transform,
            Comp.Battle.Bullet,
            Comp.Battle.Ray,
            Comp.Common.DistroyTimer
        ],
        (e) => {
            // 获取发射实体的位置和力信息
            const ownerTransform = ownerEntity.component(Comp.Transform)
            const force = ownerEntity.component(Comp.Force)
            // 获取新创建的子弹实体的Transform组件
            const bulletTransform = e.component(Comp.Transform)
            // 获取目标实体的位置信息
            const targetTransform = target.component(Comp.Transform)
            const targetPos = targetTransform.pos
            /**激光 */
            const ray = e.component(Comp.Battle.Ray)


            // 设置子弹的起始位置
            const startPos = ownerTransform.pos
            Vect3.set(bulletTransform.pos, startPos)
            /**一个向上的偏移，让子弹比起点位置靠上一点 */
            Vect3.add(bulletTransform.pos, bulletTransform.pos, Vect3.set(Comp.Transform.tempVec3, 0, ownerTransform.height / 2, 0))

            // 计算子弹的运动方向
            const direction = Vect3.subtract(Comp.Transform.tempVec3, targetPos, bulletTransform.pos)
            Vect3.normalize(direction, direction)
            // 获取并设置子弹的其他属性
            Vect3.set(bulletTransform.orientation, direction)



            ray.targetEntityId = target.id
            Vect3.set(ray.startPos, bulletTransform.pos)
            Vect3.set(ray.targetPos, targetPos)

            Comp.Common.DistroyTimer.init(e, world, 1000)

            const battleAttri = e.component(Comp.Battle.Attri)
            const atp = Comp.Battle.Attri.getValue(battleAttri, EHeroAttri.atp)
            const bullet = e.component(Comp.Battle.Bullet)
            bullet.emmiterId = ownerEntity.id
            bullet.atp = atp


        }
    )

    return bullet
}



export function getDistance(transform: Comp.Transform, targetTransform: Comp.Transform) {
    return Vect3.distance(transform.pos, targetTransform.pos) - targetTransform.radius
}

/**
 * 检查给定实体是否符合一系列目标条件。
 * 
 * @param entity - EcsEntity 实体对象，是被检查的对象。
 * @param targetConditionList - FindTargetCondition[] 目标条件列表，用于检查实体是否符合这些条件。
 * @returns boolean - 如果实体完全符合所有给定的目标条件，则返回true；如果目标条件列表为空，也返回true；否则返回false。
 */
export function matchFindTargetConditionList(entity: EcsEntity, targetConditionList: FindTargetCondition[]) {
    // 如果目标条件列表为空，直接返回true，视为实体符合所有条件
    if (targetConditionList.length == 0) { return true }
    // 检查实体是否符合每一个条件，只要有一个条件不满足则返回false
    const result = targetConditionList.every(condition => {
        return findTargetConditionMatcher[condition.attriType](entity, condition)
    })
    return result
}

// export function matchFindTargetCondition(entity: EcsEntity, targetCondition: FindTargetCondition) {
//     switch (targetCondition.attriType) {
//         case EFindTargetAttriType.force:
//             const force = entity.component(Comp.Force)
//             break;
//         case EFindTargetAttriType.force:
//             const force = entity.component(Comp.Force)
//             break;
//         default:
//             break;
//     }
// }


export const findTargetConditionMatcher = {
    [EFindTargetConditionAttriType.force]: (entity: EcsEntity, targetCondition: FindTargetCondition) => {
        const force = entity.component(Comp.Force)
        if (!force) return false
        const r = findTargetValueMatcher[targetCondition.matchType](force.value, targetCondition.value)
        return r
    },
    [EFindTargetConditionAttriType.hpPercent]: (entity: EcsEntity, targetCondition: FindTargetCondition) => {
        const battleInfo = entity.component(Comp.Battle.BattleInfo)
        const battleAttri = entity.component(Comp.Battle.Attri)
        const hp = Comp.Battle.Attri.getValue(battleAttri, EHeroAttri.hp)
        if (!battleInfo) return false
        return findTargetValueMatcher[targetCondition.matchType](battleInfo.curHp / hp, targetCondition.value)
    }
}

export const findTargetValueMatcher = {
    [EFindTargetMatchOpType.equals]: (value: number, conditionValue: number) => {
        return value == conditionValue
    },
    [EFindTargetMatchOpType.greater]: (value: number, conditionValue: number) => {
        return value > conditionValue
    },
    [EFindTargetMatchOpType.less]: (value: number, conditionValue: number) => {
        return value < conditionValue
    },
    [EFindTargetMatchOpType.greaterOrEquals]: (value: number, conditionValue: number) => {
        return value >= conditionValue
    },
    [EFindTargetMatchOpType.lessOrEquals]: (value: number, conditionValue: number) => {
        return value <= conditionValue
    }
}

export function getLogicTargets(world: EcsWorld, entity: EcsEntity, logic: HeroLogic, parentTargets?: EcsEntity[]) {

    const matcher = getFindTargetMatcher(logic)
    if (!matcher) {
        let aa = 1
    }
    return matcher(world, entity, logic, parentTargets)
}

export function getFindTargetMatcher(logic: HeroLogic): (world: EcsWorld, entity: EcsEntity, logic: HeroLogic, parentTargets?: EcsEntity[]) => EcsEntity[] {
    return findTargetMatcher[logic.target.t]
}

/**寻找目标匹配器 */
export const findTargetMatcher = {
    [EHeroTargetMatchType.self]: (world: EcsWorld, entity: EcsEntity, logic: HeroLogic, parentTargets?: EcsEntity[]) => {
        return [entity]
    },
    [EHeroTargetMatchType.actionTarget]: (world: EcsWorld, entity: EcsEntity, logic: HeroLogic, parentTargets?: EcsEntity[]) => {
        const action = entity.component(Comp.HeroAction)

        const target = world.getEntity(action.targetId)
        if (target) {
            return [target]
        } else {
            return []
        }
    },
    [EHeroTargetMatchType.allEnemy]: (world: EcsWorld, entity: EcsEntity, logic: HeroLogic, parentTargets?: EcsEntity[]) => {
        const group = world.getGroupByClz(Comp.Hero)
        return group.entities.filter(
            i => i.id != entity.id
        )
    },
    [EHeroTargetMatchType.enemyInTargetRange]: (world: EcsWorld, entity: EcsEntity, logic: HeroLogic, parentTargets?: EcsEntity[]) => {
        const group = world.getGroupByClz(Comp.Hero)
        const action = entity.component(Comp.HeroAction)
        const target = world.getEntity(action.targetId)
        if (!target) {
            return []
        }
        const distance = Number(logic.target.range)
        return group.entities.filter(
            i => i.id != entity.id && getDistance(i.component(Comp.Transform), target.component(Comp.Transform)) < distance
        )
    },
    [EHeroTargetMatchType.parentLogic]: (world: EcsWorld, entity: EcsEntity, logic: HeroLogic, parentTargets?: EcsEntity[]) => {
        return parentTargets
    }
}

/**英雄是否处于特殊状态 */
export function isHeroInSpecialState(world: EcsWorld, entity: EcsEntity, state: EHeroSpecialState) {
    const buffContainerComp = entity.component(Comp.Battle.BuffContainer)
    const buff = buffContainerComp.buffList.find(i => {
        const buff = world.getEntity(i).component(Comp.Battle.Buff)
        const cfg = gg.cfgById(GpCfg.Buff, buff.cfgId)
        return cfg.specailState[state]
    })
    return !!buff

}


export function onTriggerLogic(world: EcsWorld, entity: EcsEntity, logic: HeroLogic, parentTargets?: EcsEntity[]) {
    const logicFn = logicMap[logic.logicType]
    let entities = parentTargets || [entity]
    if (logicFn) {
        if (logic.target) {
            entities = getLogicTargets(world, entity, logic, parentTargets)
        }

        if (entities) {
            entities.forEach(i => {
                logicFn(world, entity, i, logic)
            })
        }

    }
    if (logic.subLogics && logic.subLogics.length > 0) {
        logic.subLogics.forEach(subLogic => {
            onTriggerLogic(world, entity, subLogic, entities)
        })
    }
}

export const logicMap: { [t: string]: (world: EcsWorld, entity: EcsEntity, targetEntity: EcsEntity, logic: HeroLogic) => void } = {
    [EHeroLogicType.findTargets]: (world, entity, targetEntity: EcsEntity, logic) => {
    },
    [EHeroLogicType.att]: (world, entity, targetEntity: EcsEntity, logic) => {
        const action = entity.component(Comp.HeroAction)
        const target = world.getEntity(action.targetId)
        if (target) {
            world.system(BattleSystem).onTriggerAttTimePoint(entity, entity.component(Comp.Battle.BattleInfo), target, target.component(Comp.Battle.BattleInfo))
            if (!world.getEntity(action.targetId)) {
                action.nextActionId = 0
            }
        }
    },
    [EHeroLogicType.cure]: (world, entity, targetEntity: EcsEntity, logic) => {
        const action = entity.component(Comp.HeroAction)
        cure(new CureEventInfo(world, entity, entity.component(Comp.Battle.BattleInfo), targetEntity, targetEntity.component(Comp.Battle.BattleInfo)))
        if (!world.getEntity(action.targetId)) {
            action.nextActionId = 0
        }
    },
    [EHeroLogicType.addBuff]: (world, entity, targetEntity: EcsEntity, logic) => {
        const buffId = logic.data.buffId
        const buffCfg = gg.cfgById(GpCfg.Buff, buffId)
        world.system(BuffSystem).addBuff(targetEntity, buffCfg)
    },
    [EHeroLogicType.modifyAttri]: (world, entity, targetEntity: EcsEntity, logic) => {
        const attriId = logic.data.t
        const value = logic.data.v
        const operation = logic.data.o || EHeroAttriModifyType.add
        const valueType = logic.data.vt || EHeroAttriOperationType.add
        const modifyIndex = logic.data.index || 0
        const attriCommp = targetEntity.component(Comp.Battle.Attri)
        Comp.Battle.Attri.modify(attriCommp, attriId, value, operation, modifyIndex, valueType)
    },
    [EHeroLogicType.aoe]: (world, entity, targetEntity: EcsEntity, logic) => {
        const targetBattleInfo = targetEntity.component(Comp.Battle.BattleInfo)
        const battleInfo = entity.component(Comp.Battle.BattleInfo)
        makeDamage(new DamageEventInfo(world, entity, battleInfo, targetEntity, targetBattleInfo, 0, true))
    },
    [EHeroLogicType.playSound]: (world, entity, targetEntity: EcsEntity, logic: HeroLogic) => {
        gg.eventTarget.emit(GpEventDef.playSound, logic.data)
    },
    [EHeroLogicType.playEff]: (world, entity, targetEntity: EcsEntity, logic) => {
        gg.eventTarget.emit(GpEventDef.playEff, new PlayEffEventData(entity, logic, targetEntity))
    }
}
